home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / lib / tk2.3 / dist / tkWindow.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-21  |  42.9 KB  |  1,528 lines

  1. /* 
  2.  * tkWindow.c --
  3.  *
  4.  *    This file provides basic window-manipulation procedures,
  5.  *    which are equivalent to procedures in Xlib (and even
  6.  *    invoke them) but also maintain the local Tk_Window
  7.  *    structure.
  8.  *
  9.  * Copyright 1989-1992 Regents of the University of California.
  10.  * Permission to use, copy, modify, and distribute this
  11.  * software and its documentation for any purpose and without
  12.  * fee is hereby granted, provided that the above copyright
  13.  * notice appear in all copies.  The University of California
  14.  * makes no representations about the suitability of this
  15.  * software for any purpose.  It is provided "as is" without
  16.  * express or implied warranty.
  17.  */
  18.  
  19. #ifndef lint
  20. static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkWindow.c,v 1.92 92/08/21 11:42:44 ouster Exp $ SPRITE (Berkeley)";
  21. #endif
  22.  
  23. #include "tkConfig.h"
  24. #include "tkInt.h"
  25.  
  26. /*
  27.  * Count of number of main windows currently open in this process.
  28.  */
  29.  
  30. int tk_NumMainWindows;
  31.  
  32. /*
  33.  * List of all displays currently in use.
  34.  */
  35.  
  36. TkDisplay *tkDisplayList = NULL;
  37.  
  38. /*
  39.  * Have statics in this module been initialized?
  40.  */
  41.  
  42. static initialized = 0;
  43.  
  44. /*
  45.  * Context information used to map from X window id's to
  46.  * TkWindow structures (during event handling, for example):
  47.  */
  48.  
  49. XContext tkWindowContext;
  50.  
  51. /*
  52.  * The variables below hold several uid's that are used in many places
  53.  * in the toolkit.
  54.  */
  55.  
  56. Tk_Uid tkDisabledUid = NULL;
  57. Tk_Uid tkActiveUid = NULL;
  58. Tk_Uid tkNormalUid = NULL;
  59.  
  60. /*
  61.  * Default values for "changes" and "atts" fields of TkWindows.  Note
  62.  * that Tk always requests all events for all windows, except StructureNotify
  63.  * events on internal windows:  these events are generated internally.
  64.  */
  65.  
  66. static XWindowChanges defChanges = {
  67.     0, 0, 1, 1, 0, 0, Above
  68. };
  69. #define ALL_EVENTS_MASK \
  70.     KeyPressMask|KeyReleaseMask|ButtonPressMask|ButtonReleaseMask| \
  71.     EnterWindowMask|LeaveWindowMask|PointerMotionMask|ExposureMask| \
  72.     VisibilityChangeMask|SubstructureNotifyMask| \
  73.     FocusChangeMask|PropertyChangeMask|ColormapChangeMask
  74. static XSetWindowAttributes defAtts= {
  75.     None,            /* background_pixmap */
  76.     0,                /* background_pixel */
  77.     CopyFromParent,        /* border_pixmap */
  78.     0,                /* border_pixel */
  79.     ForgetGravity,        /* bit_gravity */
  80.     NorthWestGravity,        /* win_gravity */
  81.     NotUseful,            /* backing_store */
  82.     ~0,                /* backing_planes */
  83.     0,                /* backing_pixel */
  84.     False,            /* save_under */
  85.     ALL_EVENTS_MASK,        /* event_mask */
  86.     0,                /* do_not_propagate_mask */
  87.     False,            /* override_redirect */
  88.     CopyFromParent,        /* colormap */
  89.     None            /* cursor */
  90. };
  91.  
  92. /*
  93.  * The following structure defines all of the commands supported by
  94.  * Tk, and the C procedures that execute them.
  95.  */
  96.  
  97. typedef struct {
  98.     char *name;            /* Name of command. */
  99.     int (*cmdProc) _ANSI_ARGS_((ClientData clientData, Tcl_Interp *interp,
  100.         int argc, char **argv));
  101.                 /* Command procedure. */
  102. } TkCmd;
  103.  
  104. TkCmd commands[] = {
  105.     /*
  106.      * Commands that are part of the intrinsics:
  107.      */
  108.  
  109.     {"after",        Tk_AfterCmd},
  110.     {"bind",        Tk_BindCmd},
  111.     {"destroy",        Tk_DestroyCmd},
  112.     {"focus",        Tk_FocusCmd},
  113.     {"grab",        Tk_GrabCmd},
  114.     {"option",        Tk_OptionCmd},
  115.     {"pack",        Tk_PackCmd},
  116.     {"place",        Tk_PlaceCmd},
  117.     {"selection",    Tk_SelectionCmd},
  118.     {"tkwait",        Tk_TkwaitCmd},
  119.     {"update",        Tk_UpdateCmd},
  120.     {"winfo",        Tk_WinfoCmd},
  121.     {"wm",        Tk_WmCmd},
  122.  
  123.     /*
  124.      * Widget-creation commands.
  125.      */
  126.     {"button",        Tk_ButtonCmd},
  127.     {"canvas",        Tk_CanvasCmd},
  128.     {"checkbutton",    Tk_ButtonCmd},
  129.     {"entry",        Tk_EntryCmd},
  130.     {"frame",        Tk_FrameCmd},
  131.     {"label",        Tk_ButtonCmd},
  132.     {"listbox",        Tk_ListboxCmd},
  133.     {"menu",        Tk_MenuCmd},
  134.     {"menubutton",    Tk_MenubuttonCmd},
  135.     {"message",        Tk_MessageCmd},
  136.     {"radiobutton",    Tk_ButtonCmd},
  137.     {"scale",        Tk_ScaleCmd},
  138.     {"scrollbar",    Tk_ScrollbarCmd},
  139.     {"text",        Tk_TextCmd},
  140.     {"toplevel",    Tk_FrameCmd},
  141.     {(char *) NULL,    (int (*)()) NULL}
  142. };
  143.  
  144. /*
  145.  * Forward declarations to procedures defined later in this file:
  146.  */
  147.  
  148. static Tk_Window    CreateTopLevelWindow _ANSI_ARGS_((Tcl_Interp *interp,
  149.                 Tk_Window parent, char *name, char *screenName));
  150. static void        DoConfigureNotify _ANSI_ARGS_((TkWindow *winPtr));
  151. static TkDisplay *    GetScreen _ANSI_ARGS_((Tcl_Interp *interp,
  152.                 char *screenName, int *screenPtr));
  153. static int        NameWindow _ANSI_ARGS_((Tcl_Interp *interp,
  154.                 TkWindow *winPtr, TkWindow *parentPtr,
  155.                 char *name));
  156. static TkWindow    *    NewWindow _ANSI_ARGS_((TkDisplay *dispPtr,
  157.                 int screenNum));
  158.  
  159. /*
  160.  *----------------------------------------------------------------------
  161.  *
  162.  * CreateTopLevelWindow --
  163.  *
  164.  *    Make a new window that will be at top-level (its parent will
  165.  *    be the root window of a screen).
  166.  *
  167.  * Results:
  168.  *    The return value is a token for the new window, or NULL if
  169.  *    an error prevented the new window from being created.  If
  170.  *    NULL is returned, an error message will be left in
  171.  *    interp->result.
  172.  *
  173.  * Side effects:
  174.  *    A new window structure is allocated locally.  An X
  175.  *    window is NOT initially created, but will be created
  176.  *    the first time the window is mapped.
  177.  *
  178.  *----------------------------------------------------------------------
  179.  */
  180.  
  181. static Tk_Window
  182. CreateTopLevelWindow(interp, parent, name, screenName)
  183.     Tcl_Interp *interp;        /* Interpreter to use for error reporting. */
  184.     Tk_Window parent;        /* Token for logical parent of new window
  185.                  * (used for naming, options, etc.).  May
  186.                  * be NULL. */
  187.     char *name;            /* Name for new window;  if parent is
  188.                  * non-NULL, must be unique among parent's
  189.                  * children. */
  190.     char *screenName;        /* Name of screen on which to create
  191.                  * window.  NULL means use DISPLAY environment
  192.                  * variable to determine.  Empty string means
  193.                  * use parent's screen, or DISPLAY if no
  194.                  * parent. */
  195. {
  196.     register TkWindow *winPtr;
  197.     register TkDisplay *dispPtr;
  198.     int screenId;
  199.  
  200.     if (!initialized) {
  201.     initialized = 1;
  202.     tkWindowContext = XUniqueContext();
  203.     tkActiveUid = Tk_GetUid("active");
  204.     tkDisabledUid = Tk_GetUid("disabled");
  205.     tkNormalUid = Tk_GetUid("normal");
  206.     }
  207.  
  208.     if ((parent != NULL) && (screenName != NULL) && (screenName[0] == '\0')) {
  209.     dispPtr = ((TkWindow *) parent)->dispPtr;
  210.     screenId = Tk_ScreenNumber(parent);
  211.     } else {
  212.     dispPtr = GetScreen(interp, screenName, &screenId);
  213.     if (dispPtr == NULL) {
  214.         return (Tk_Window) NULL;
  215.     }
  216.     }
  217.  
  218.     winPtr = NewWindow(dispPtr, screenId);
  219.  
  220.     /*
  221.      * Internal windows don't normally ask for StructureNotify events,
  222.      * since we can generate them internally.  However, for top-level
  223.      * windows we need to as for the events because the window could
  224.      * be manipulated externally.
  225.      */
  226.  
  227.     winPtr->atts.event_mask |= StructureNotifyMask;
  228.  
  229.     /*
  230.      * (Need to set the TK_TOP_LEVEL flag immediately here;  otherwise
  231.      * Tk_DestroyWindow will core dump if it is called before the flag
  232.      * has been set.)
  233.      */
  234.  
  235.     winPtr->flags |= TK_TOP_LEVEL;
  236.     if (parent != NULL) {
  237.     if (NameWindow(interp, winPtr, (TkWindow *) parent, name) != TCL_OK) {
  238.         Tk_DestroyWindow((Tk_Window) winPtr);
  239.         return (Tk_Window) NULL;
  240.     }
  241.     }
  242.     TkWmNewWindow(winPtr);
  243.     return (Tk_Window) winPtr;
  244. }
  245.  
  246. /*
  247.  *----------------------------------------------------------------------
  248.  *
  249.  * GetScreen --
  250.  *
  251.  *    Given a string name for a display-plus-screen, find the
  252.  *    TkDisplay structure for the display and return the screen
  253.  *    number too.
  254.  *
  255.  * Results:
  256.  *    The return value is a pointer to information about the display,
  257.  *    or NULL if the display couldn't be opened.  In this case, an
  258.  *    error message is left in interp->result.  The location at
  259.  *    *screenPtr is overwritten with the screen number parsed from
  260.  *    screenName.
  261.  *
  262.  * Side effects:
  263.  *    A new connection is opened to the display if there is no
  264.  *    connection already.  A new TkDisplay data structure is also
  265.  *    setup, if necessary.
  266.  *
  267.  *----------------------------------------------------------------------
  268.  */
  269.  
  270. static TkDisplay *
  271. GetScreen(interp, screenName, screenPtr)
  272.     Tcl_Interp *interp;        /* Place to leave error message. */
  273.     char *screenName;        /* Name for screen.  NULL or empty means
  274.                  * use DISPLAY envariable. */
  275.     int *screenPtr;        /* Where to store screen number. */
  276. {
  277.     register TkDisplay *dispPtr;
  278.     char *p;
  279.     int length, screenId;
  280.  
  281.     /*
  282.      * Separate the screen number from the rest of the display
  283.      * name.  ScreenName is assumed to have the syntax
  284.      * <display>.<screen> with the dot and the screen being
  285.      * optional.
  286.      */
  287.  
  288.     if ((screenName == NULL) || (screenName[0] == '\0')) {
  289.     screenName = getenv("DISPLAY");
  290.     if (screenName == NULL) {
  291.         interp->result =
  292.             "no display name and no $DISPLAY environment variable";
  293.         return (TkDisplay *) NULL;
  294.     }
  295.     }
  296.     length = strlen(screenName);
  297.     screenId = 0;
  298.     p = screenName+length-1;
  299.     while (isdigit(*p) && (p != screenName)) {
  300.     p--;
  301.     }
  302.     if ((*p == '.') && (p[1] != '\0')) {
  303.     length = p - screenName;
  304.     screenId = strtoul(p+1, (char **) NULL, 10);
  305.     }
  306.  
  307.     /*
  308.      * See if we already have a connection to this display.  If not,
  309.      * then open a new connection.
  310.      */
  311.  
  312.     for (dispPtr = tkDisplayList; ; dispPtr = dispPtr->nextPtr) {
  313.     if (dispPtr == NULL) {
  314.         Display *display;
  315.  
  316.         display = XOpenDisplay(screenName);
  317.         if (display == NULL) {
  318.         Tcl_AppendResult(interp, "couldn't connect to display \"",
  319.             screenName, "\"", (char *) NULL);
  320.         return (TkDisplay *) NULL;
  321.         }
  322.         dispPtr = (TkDisplay *) ckalloc(sizeof(TkDisplay));
  323.         dispPtr->display = display;
  324.         dispPtr->nextPtr = tkDisplayList;
  325.         dispPtr->name = (char *) ckalloc((unsigned) (length+1));
  326.         dispPtr->lastEventTime = CurrentTime;
  327.         strncpy(dispPtr->name, screenName, length);
  328.         dispPtr->mouseMainPtr = NULL;
  329.         dispPtr->name[length] = '\0';
  330.         dispPtr->symsPerCode = 0;
  331.         dispPtr->errorPtr = NULL;
  332.         dispPtr->deleteCount = 0;
  333.         dispPtr->commWindow = NULL;
  334.         dispPtr->selectionOwner = NULL;
  335.         dispPtr->selectionSerial = 0;
  336.         dispPtr->multipleAtom = None;
  337.         dispPtr->atomInit = 0;
  338.         dispPtr->cursorFont = None;
  339.         dispPtr->grabWinPtr = NULL;
  340.         dispPtr->ungrabWinPtr = NULL;
  341.         dispPtr->buttonWinPtr = NULL;
  342.         dispPtr->pointerWinPtr = NULL;
  343.         dispPtr->serverWinPtr = NULL;
  344.         dispPtr->grabFlags = 0;
  345.         tkDisplayList = dispPtr;
  346.         Tk_CreateFileHandler(ConnectionNumber(display),
  347.             TK_READABLE, (void (*)()) NULL,
  348.             (ClientData) display);
  349.         break;
  350.     }
  351.     if ((strncmp(dispPtr->name, screenName, length) == 0)
  352.         && (dispPtr->name[length] == '\0')) {
  353.         break;
  354.     }
  355.     }
  356.     if (screenId >= ScreenCount(dispPtr->display)) {
  357.     sprintf(interp->result, "bad screen number \"%d\"", screenId);
  358.     return (TkDisplay *) NULL;
  359.     }
  360.     *screenPtr = screenId;
  361.     return dispPtr;
  362. }
  363.  
  364. /*
  365.  *--------------------------------------------------------------
  366.  *
  367.  * NewWindow --
  368.  *
  369.  *    This procedure creates and initializes a TkWindow structure.
  370.  *
  371.  * Results:
  372.  *    The return value is a pointer to the new window.
  373.  *
  374.  * Side effects:
  375.  *    A new window structure is allocated and all its fields are
  376.  *    initialized.
  377.  *
  378.  *--------------------------------------------------------------
  379.  */
  380.  
  381. static TkWindow *
  382. NewWindow(dispPtr, screenNum)
  383.     TkDisplay *dispPtr;        /* Display associated with new window. */
  384.     int screenNum;        /* Index of screen for new window. */
  385. {
  386.     register TkWindow *winPtr;
  387.  
  388.     winPtr = (TkWindow *) ckalloc(sizeof(TkWindow));
  389.     winPtr->display = dispPtr->display;
  390.     winPtr->dispPtr = dispPtr;
  391.     winPtr->screenNum = screenNum;
  392.     winPtr->window = None;
  393.     winPtr->childList = NULL;
  394.     winPtr->parentPtr = NULL;
  395.     winPtr->nextPtr = NULL;
  396.     winPtr->mainPtr = NULL;
  397.     winPtr->pathName = NULL;
  398.     winPtr->nameUid = NULL;
  399.     winPtr->classUid = NULL;
  400.     winPtr->changes = defChanges;
  401.     winPtr->dirtyChanges = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
  402.     winPtr->atts = defAtts;
  403.     winPtr->dirtyAtts = CWEventMask;
  404.     winPtr->flags = 0;
  405.     winPtr->handlerList = NULL;
  406.     winPtr->focusProc = NULL;
  407.     winPtr->focusData = NULL;
  408.     winPtr->optionLevel = -1;
  409.     winPtr->selHandlerList = NULL;
  410.     winPtr->selClearProc = NULL;
  411.     winPtr->selClearData = NULL;
  412.     winPtr->geomProc = NULL;
  413.     winPtr->geomData = NULL;
  414.     winPtr->reqWidth = winPtr->reqHeight = 0;
  415.     winPtr->internalBorderWidth = 0;
  416.     winPtr->wmInfoPtr = NULL;
  417.     return winPtr;
  418. }
  419.  
  420. /*
  421.  *----------------------------------------------------------------------
  422.  *
  423.  * NameWindow --
  424.  *
  425.  *    This procedure is invoked to give a window a name and insert
  426.  *    the window into the hierarchy associated with a particular
  427.  *    application.
  428.  *
  429.  * Results:
  430.  *    A standard Tcl return value.
  431.  *
  432.  * Side effects:
  433.  *      See above.
  434.  *
  435.  *----------------------------------------------------------------------
  436.  */
  437.  
  438. static int
  439. NameWindow(interp, winPtr, parentPtr, name)
  440.     Tcl_Interp *interp;        /* Interpreter to use for error reporting. */
  441.     register TkWindow *winPtr;    /* Window that is to be named and inserted. */
  442.     TkWindow *parentPtr;    /* Pointer to logical parent for winPtr
  443.                  * (used for naming, options, etc.). */
  444.     char *name;            /* Name for winPtr;   must be unique among
  445.                  * parentPtr's children. */
  446. {
  447. #define FIXED_SIZE 200
  448.     char staticSpace[FIXED_SIZE];
  449.     char *pathName;
  450.     int new;
  451.     Tcl_HashEntry *hPtr;
  452.     int length1, length2;
  453.  
  454.     /*
  455.      * Setup all the stuff except name right away, then do the name stuff
  456.      * last.  This is so that if the name stuff fails, everything else
  457.      * will be properly initialized (needed to destroy the window cleanly
  458.      * after the naming failure).
  459.      */
  460.     winPtr->parentPtr = parentPtr;
  461.     winPtr->nextPtr = parentPtr->childList;
  462.     parentPtr->childList = winPtr;
  463.     winPtr->mainPtr = parentPtr->mainPtr;
  464.     winPtr->nameUid = Tk_GetUid(name);
  465.  
  466.     /*
  467.      * To permit names of arbitrary length, must be prepared to malloc
  468.      * a buffer to hold the new path name.  To run fast in the common
  469.      * case where names are short, use a fixed-size buffer on the
  470.      * stack.
  471.      */
  472.  
  473.     length1 = strlen(parentPtr->pathName);
  474.     length2 = strlen(name);
  475.     if ((length1+length2+2) <= FIXED_SIZE) {
  476.     pathName = staticSpace;
  477.     } else {
  478.     pathName = (char *) ckalloc((unsigned) (length1+length2+2));
  479.     }
  480.     if (length1 == 1) {
  481.     pathName[0] = '.';
  482.     strcpy(pathName+1, name);
  483.     } else {
  484.     strcpy(pathName, parentPtr->pathName);
  485.     pathName[length1] = '.';
  486.     strcpy(pathName+length1+1, name);
  487.     }
  488.     hPtr = Tcl_CreateHashEntry(&parentPtr->mainPtr->nameTable, pathName, &new);
  489.     if (pathName != staticSpace) {
  490.     ckfree(pathName);
  491.     }
  492.     if (!new) {
  493.     Tcl_AppendResult(interp, "window name \"", name,
  494.         "\" already exists in parent", (char *) NULL);
  495.     return TCL_ERROR;
  496.     }
  497.     Tcl_SetHashValue(hPtr, winPtr);
  498.     winPtr->pathName = Tcl_GetHashKey(&parentPtr->mainPtr->nameTable, hPtr);
  499.     return TCL_OK;
  500. }
  501.  
  502. /*
  503.  *----------------------------------------------------------------------
  504.  *
  505.  * Tk_CreateMainWindow --
  506.  *
  507.  *    Make a new main window.  A main window is a special kind of
  508.  *    top-level window used as the outermost window in an
  509.  *    application.
  510.  *
  511.  * Results:
  512.  *    The return value is a token for the new window, or NULL if
  513.  *    an error prevented the new window from being created.  If
  514.  *    NULL is returned, an error message will be left in
  515.  *    interp->result.
  516.  *
  517.  * Side effects:
  518.  *    A new window structure is allocated locally;  "interp" is
  519.  *    associated with the window and registered for "send" commands
  520.  *    under "baseName".  BaseName may be extended with an instance
  521.  *    number in the form "#2" if necessary to make it globally
  522.  *    unique.  Tk-related commands are bound into interp.  An X
  523.  *    window is NOT initially created, but will be created the
  524.  *    first time the window is mapped.
  525.  *
  526.  *----------------------------------------------------------------------
  527.  */
  528.  
  529. Tk_Window
  530. Tk_CreateMainWindow(interp, screenName, baseName)
  531.     Tcl_Interp *interp;        /* Interpreter to use for error reporting. */
  532.     char *screenName;        /* Name of screen on which to create
  533.                  * window.  Empty or NULL string means
  534.                  * use DISPLAY environment variable. */
  535.     char *baseName;        /* Base name for application;  usually of the
  536.                  * form "prog instance". */
  537. {
  538.     Tk_Window tkwin;
  539.     int result, dummy;
  540.     Tcl_HashEntry *hPtr;
  541.     register TkMainInfo *mainPtr;
  542.     register TkWindow *winPtr;
  543.     register TkCmd *cmdPtr;
  544.  
  545.     /*
  546.      * Create the basic TkWindow structure.
  547.      */
  548.  
  549.     tkwin = CreateTopLevelWindow(interp, (Tk_Window) NULL, baseName,
  550.         screenName);
  551.     if (tkwin == NULL) {
  552.     return NULL;
  553.     }
  554.  
  555.     /*
  556.      * Create the TkMainInfo structure for this application, and set
  557.      * up name-related information for the new window.
  558.      */
  559.  
  560.     winPtr = (TkWindow *) tkwin;
  561.     mainPtr = (TkMainInfo *) ckalloc(sizeof(TkMainInfo));
  562.     mainPtr->winPtr = winPtr;
  563.     mainPtr->interp = interp;
  564.     Tcl_InitHashTable(&mainPtr->nameTable, TCL_STRING_KEYS);
  565.     mainPtr->bindingTable = Tk_CreateBindingTable(interp);
  566.     mainPtr->focusPtr = NULL;
  567.     mainPtr->optionRootPtr = NULL;
  568.     winPtr->mainPtr = mainPtr;
  569.     hPtr = Tcl_CreateHashEntry(&mainPtr->nameTable, ".", &dummy);
  570.     Tcl_SetHashValue(hPtr, winPtr);
  571.     winPtr->pathName = Tcl_GetHashKey(&mainPtr->nameTable, hPtr);
  572.  
  573.     /*
  574.      * Register the interpreter for "send" purposes.  If baseName isn't
  575.      * already unique, find a unique suffix to add to it to make it
  576.      * unique.  Change the window's name to contain the suffix.
  577.      */
  578.  
  579.     result = Tk_RegisterInterp(interp, baseName, tkwin);
  580.     if (result == TCL_OK) {
  581.     winPtr->nameUid = Tk_GetUid(baseName);
  582.     } else {
  583.     char newName[110];
  584.     int i;
  585.  
  586.     for (i = 2; ; i++) {
  587.         sprintf(newName, "%.100s #%d", baseName, i);
  588.         Tcl_SetResult(interp, (char *) NULL, TCL_STATIC);
  589.         result = Tk_RegisterInterp(interp, newName, tkwin);
  590.         if (result == TCL_OK) {
  591.         break;
  592.         }
  593.         if (i >= 100) {
  594.         Tcl_SetResult(interp,
  595.             "couldn't generate unique name to register application",
  596.             TCL_STATIC);
  597.         Tk_DestroyWindow(tkwin);
  598.         }
  599.     }
  600.     winPtr->nameUid = Tk_GetUid(newName);
  601.     }
  602.  
  603.     /*
  604.      * Bind in Tk's commands.
  605.      */
  606.  
  607.     for (cmdPtr = commands; cmdPtr->name != NULL; cmdPtr++) {
  608.     Tcl_CreateCommand(interp, cmdPtr->name, cmdPtr->cmdProc,
  609.         (ClientData) tkwin, (void (*)()) NULL);
  610.     }
  611.  
  612.     /*
  613.      * Set variables for the intepreter.
  614.      */
  615.  
  616.     Tcl_SetVar(interp, "tk_library", TK_LIBRARY, TCL_GLOBAL_ONLY);
  617.     Tcl_SetVar(interp, "tk_version", TK_VERSION, TCL_GLOBAL_ONLY);
  618.     Tcl_SetVar(interp, "tkVersion", TK_VERSION, TCL_GLOBAL_ONLY);
  619.  
  620.     tk_NumMainWindows++;
  621.     return tkwin;
  622. }
  623.  
  624. /*
  625.  *--------------------------------------------------------------
  626.  *
  627.  * Tk_CreateWindow --
  628.  *
  629.  *    Create a new internal or top-level window as a child of an
  630.  *    existing window.
  631.  *
  632.  * Results:
  633.  *    The return value is a token for the new window.  This
  634.  *    is not the same as X's token for the window.  If an error
  635.  *    occurred in creating the window (e.g. no such display or
  636.  *    screen), then an error message is left in interp->result and
  637.  *    NULL is returned.
  638.  *
  639.  * Side effects:
  640.  *    A new window structure is allocated locally.  An X
  641.  *    window is not initially created, but will be created
  642.  *    the first time the window is mapped.
  643.  *
  644.  *--------------------------------------------------------------
  645.  */
  646.  
  647. Tk_Window
  648. Tk_CreateWindow(interp, parent, name, screenName)
  649.     Tcl_Interp *interp;        /* Interpreter to use for error reporting.
  650.                  * Interp->result is assumed to be
  651.                  * initialized by the caller. */
  652.     Tk_Window parent;        /* Token for parent of new window. */
  653.     char *name;            /* Name for new window.  Must be unique
  654.                  * among parent's children. */
  655.     char *screenName;        /* If NULL, new window will be internal on
  656.                  * same screen as its parent.  If non-NULL,
  657.                  * gives name of screen on which to create
  658.                  * new window;  window will be a top-level
  659.                  * window. */
  660. {
  661.     TkWindow *parentPtr = (TkWindow *) parent;
  662.     TkWindow *winPtr;
  663.  
  664.     if (screenName == NULL) {
  665.     winPtr = NewWindow(parentPtr->dispPtr, parentPtr->screenNum);
  666.     if (NameWindow(interp, winPtr, parentPtr, name) != TCL_OK) {
  667.         Tk_DestroyWindow((Tk_Window) winPtr);
  668.         return NULL;
  669.     } else {
  670.         return (Tk_Window) winPtr;
  671.     }
  672.     } else {
  673.     return CreateTopLevelWindow(interp, parent, name, screenName);
  674.     }
  675. }
  676.  
  677. /*
  678.  *----------------------------------------------------------------------
  679.  *
  680.  * Tk_CreateWindowFromPath --
  681.  *
  682.  *    This procedure is similar to Tk_CreateInternalWindow except
  683.  *    that it uses a path name to create the window, rather than
  684.  *    a parent and a child name.
  685.  *
  686.  * Results:
  687.  *    The return value is a token for the new window.  This
  688.  *    is not the same as X's token for the window.  If an error
  689.  *    occurred in creating the window (e.g. no such display or
  690.  *    screen), then an error message is left in interp->result and
  691.  *    NULL is returned.
  692.  *
  693.  * Side effects:
  694.  *    A new window structure is allocated locally.  An X
  695.  *    window is not initially created, but will be created
  696.  *    the first time the window is mapped.
  697.  *
  698.  *----------------------------------------------------------------------
  699.  */
  700.  
  701. Tk_Window
  702. Tk_CreateWindowFromPath(interp, tkwin, pathName, screenName)
  703.     Tcl_Interp *interp;        /* Interpreter to use for error reporting.
  704.                  * Interp->result is assumed to be
  705.                  * initialized by the caller. */
  706.     Tk_Window tkwin;        /* Token for any window in application
  707.                  * that is to contain new window. */
  708.     char *pathName;        /* Path name for new window within the
  709.                  * application of tkwin.  The parent of
  710.                  * this window must already exist, but
  711.                  * the window itself must not exist. */
  712.     char *screenName;        /* If NULL, new window will be on same
  713.                  * screen as its parent.  If non-NULL,
  714.                  * gives name of screen on which to create
  715.                  * new window;  window will be a top-level
  716.                  * window. */
  717. {
  718. #define FIXED_SPACE 5
  719.     char fixedSpace[FIXED_SPACE+1];
  720.     char *p;
  721.     Tk_Window parent;
  722.     int numChars;
  723.  
  724.     /*
  725.      * Strip the parent's name out of pathName (it's everything up
  726.      * to the last dot).  There are two tricky parts: (a) must
  727.      * copy the parent's name somewhere else to avoid modifying
  728.      * the pathName string (for large names, space for the copy
  729.      * will have to be malloc'ed);  (b) must special-case the
  730.      * situation where the parent is ".".
  731.      */
  732.  
  733.     p = strrchr(pathName, '.');
  734.     if (p == NULL) {
  735.     Tcl_AppendResult(interp, "bad window path name \"", pathName,
  736.         "\"", (char *) NULL);
  737.     return NULL;
  738.     }
  739.     numChars = p-pathName;
  740.     if (numChars > FIXED_SPACE) {
  741.     p = (char *) ckalloc((unsigned) (numChars+1));
  742.     } else {
  743.     p = fixedSpace;
  744.     }
  745.     if (numChars == 0) {
  746.     *p = '.';
  747.     p[1] = '\0';
  748.     } else {
  749.     strncpy(p, pathName, numChars);
  750.     p[numChars] = '\0';
  751.     }
  752.  
  753.     /*
  754.      * Find the parent window.
  755.      */
  756.  
  757.     parent = Tk_NameToWindow(interp, p, tkwin);
  758.     if (p != fixedSpace) {
  759.     ckfree(p);
  760.     }
  761.     if (parent == NULL) {
  762.     return NULL;
  763.     }
  764.  
  765.     /*
  766.      * Create the window.
  767.      */
  768.  
  769.     if (screenName == NULL) {
  770.     TkWindow *parentPtr = (TkWindow *) parent;
  771.     TkWindow *winPtr;
  772.  
  773.     winPtr = NewWindow(parentPtr->dispPtr, parentPtr->screenNum);
  774.     if (NameWindow(interp, winPtr, parentPtr, pathName+numChars+1)
  775.         != TCL_OK) {
  776.         Tk_DestroyWindow((Tk_Window) winPtr);
  777.         return NULL;
  778.     } else {
  779.         return (Tk_Window) winPtr;
  780.     }
  781.     } else {
  782.     return CreateTopLevelWindow(interp, parent, pathName+numChars+1,
  783.         screenName);
  784.     }
  785. }
  786.  
  787. /*
  788.  *--------------------------------------------------------------
  789.  *
  790.  * Tk_DestroyWindow --
  791.  *
  792.  *    Destroy an existing window.  After this call, the caller
  793.  *    should never again use the token.
  794.  *
  795.  * Results:
  796.  *    None.
  797.  *
  798.  * Side effects:
  799.  *    The window is deleted, along with all of its children.
  800.  *    Relevant callback procedures are invoked.
  801.  *
  802.  *--------------------------------------------------------------
  803.  */
  804.  
  805. void
  806. Tk_DestroyWindow(tkwin)
  807.     Tk_Window tkwin;        /* Window to destroy. */
  808. {
  809.     register TkWindow *winPtr = (TkWindow *) tkwin;
  810.     XEvent event;
  811.  
  812.     /*
  813.      * Recursively destroy children.  The TK_RECURSIVE_DESTROY
  814.      * flags means that the child's window needn't be explicitly
  815.      * destroyed (the destroy of the parent already did it), nor
  816.      * does it need to be removed from its parent's child list,
  817.      * since the parent is being destroyed too.
  818.      */
  819.  
  820.     while (winPtr->childList != NULL) {
  821.     winPtr->childList->flags |= TK_RECURSIVE_DESTROY;
  822.     Tk_DestroyWindow((Tk_Window) winPtr->childList);
  823.     }
  824.  
  825.     /*
  826.      * Generate a DestroyNotify event.  In order for the DestroyNotify
  827.      * event to be processed correctly, need to make sure the window
  828.      * exists.  This is a bit of a kludge, and may be unnecessarily
  829.      * expensive, but without it no event handlers will get called for
  830.      * windows that don't exist yet.
  831.      */
  832.  
  833.     if (winPtr->window == None) {
  834.     Tk_MakeWindowExist(tkwin);
  835.     }
  836.     winPtr->flags |= TK_ALREADY_DEAD;
  837.     event.type = DestroyNotify;
  838.     event.xdestroywindow.serial =
  839.         LastKnownRequestProcessed(winPtr->display);
  840.     event.xdestroywindow.send_event = False;
  841.     event.xdestroywindow.display = winPtr->display;
  842.     event.xdestroywindow.event = winPtr->window;
  843.     event.xdestroywindow.window = winPtr->window;
  844.     Tk_HandleEvent(&event);
  845.  
  846.     /*
  847.      * Cleanup the data structures associated with this window.
  848.      * No need to destroy windows during recursive destroys, since
  849.      * that will happen automatically when the parent window is
  850.      * destroyed (not true for top-level windows:  must destroy
  851.      * them explicitly).
  852.      */
  853.  
  854.     if (winPtr->window != None) {
  855.     if (!(winPtr->flags & TK_RECURSIVE_DESTROY)
  856.         || (winPtr->flags & TK_TOP_LEVEL)) {
  857.         XDestroyWindow(winPtr->display, winPtr->window);
  858.     }
  859.     XDeleteContext(winPtr->display, winPtr->window, tkWindowContext);
  860.     winPtr->window = None;
  861.     }
  862.     if (winPtr->parentPtr != NULL) {
  863.     if (winPtr->parentPtr->childList == winPtr) {
  864.         winPtr->parentPtr->childList = winPtr->nextPtr;
  865.     } else {
  866.         register TkWindow *winPtr2;
  867.     
  868.         for (winPtr2 = winPtr->parentPtr->childList; ;
  869.             winPtr2 = winPtr2->nextPtr) {
  870.         if (winPtr2 == NULL) {
  871.             panic("Tk_DestroyWindow couldn't find child in parent (deleted twice?)");
  872.             break;
  873.         }
  874.         if (winPtr2->nextPtr == winPtr) {
  875.             winPtr2->nextPtr = winPtr->nextPtr;
  876.             break;
  877.         }
  878.         }
  879.     }
  880.     }
  881.     TkEventDeadWindow(winPtr);
  882.     TkOptionDeadWindow(winPtr);
  883.     TkSelDeadWindow(winPtr);
  884.     if (winPtr->flags & TK_TOP_LEVEL) {
  885.     TkWmDeadWindow(winPtr);
  886.     }
  887.     TkGrabDeadWindow(winPtr);
  888.     if (winPtr->mainPtr != NULL) {
  889.     Tk_DeleteAllBindings(winPtr->mainPtr->bindingTable,
  890.         (ClientData) winPtr->pathName);
  891.     if (winPtr->pathName != NULL) {
  892.         Tcl_DeleteHashEntry(Tcl_FindHashEntry(&winPtr->mainPtr->nameTable,
  893.             winPtr->pathName));
  894.     }
  895.     if (winPtr->mainPtr->winPtr == winPtr) {
  896.         register TkCmd *cmdPtr;
  897.  
  898.         /*
  899.          * Deleting a main window.  Delete the TkMainInfo structure too
  900.          * and replace all of Tk's commands with dummy commands that
  901.          * return errors.  Also delete the "send" command to unregister
  902.          * the interpreter.
  903.          */
  904.  
  905.         for (cmdPtr = commands; cmdPtr->name != NULL; cmdPtr++) {
  906.         Tcl_CreateCommand(winPtr->mainPtr->interp, cmdPtr->name,
  907.             TkDeadAppCmd, (ClientData) NULL, (void (*)()) NULL);
  908.         }
  909.         Tcl_CreateCommand(winPtr->mainPtr->interp, "send",
  910.             TkDeadAppCmd, (ClientData) NULL, (void (*)()) NULL);
  911.         Tcl_DeleteHashTable(&winPtr->mainPtr->nameTable);
  912.         Tk_DeleteBindingTable(winPtr->mainPtr->bindingTable);
  913.         ckfree((char *) winPtr->mainPtr);
  914.         tk_NumMainWindows--;
  915.     }
  916.     }
  917.     ckfree((char *) winPtr);
  918. }
  919.  
  920. /*
  921.  *--------------------------------------------------------------
  922.  *
  923.  * Tk_MapWindow --
  924.  *
  925.  *    Map a window within its parent.  This may require the
  926.  *    window and/or its parents to actually be created.
  927.  *
  928.  * Results:
  929.  *    None.
  930.  *
  931.  * Side effects:
  932.  *    The given window will be mapped.  Windows may also
  933.  *    be created.
  934.  *
  935.  *--------------------------------------------------------------
  936.  */
  937.  
  938. void
  939. Tk_MapWindow(tkwin)
  940.     Tk_Window tkwin;        /* Token for window to map. */
  941. {
  942.     register TkWindow *winPtr = (TkWindow *) tkwin;
  943.  
  944.     if (winPtr->flags & TK_MAPPED) {
  945.     return;
  946.     }
  947.     if (winPtr->window == None) {
  948.     Tk_MakeWindowExist(tkwin);
  949.     }
  950.     if (winPtr->flags & TK_TOP_LEVEL) {
  951.     if (!TkWmMapWindow(winPtr)) {
  952.         return;
  953.     }
  954.     } else {
  955.     /*
  956.      * Don't set the mapped flag for top-level windows:  TkWmMapWindow
  957.      * does it if appropriate (e.g. if the window is going to be non-
  958.      * iconic).
  959.      */
  960.  
  961.     winPtr->flags |= TK_MAPPED;
  962.     }
  963.     XMapWindow(winPtr->display, winPtr->window);
  964.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  965.     XEvent event;
  966.  
  967.     event.type = MapNotify;
  968.     event.xmap.serial = LastKnownRequestProcessed(winPtr->display);
  969.     event.xmap.send_event = False;
  970.     event.xmap.display = winPtr->display;
  971.     event.xmap.event = winPtr->window;
  972.     event.xmap.window = winPtr->window;
  973.     event.xmap.override_redirect = winPtr->atts.override_redirect;
  974.     Tk_HandleEvent(&event);
  975.     }
  976. }
  977.  
  978. /*
  979.  *--------------------------------------------------------------
  980.  *
  981.  * Tk_MakeWindowExist --
  982.  *
  983.  *    Ensure that a particular window actually exists.  This
  984.  *    procedure shouldn't normally need to be invoked from
  985.  *    outside the Tk package, but may be needed if someone
  986.  *    wants to manipulate a window before mapping it.
  987.  *
  988.  * Results:
  989.  *    None.
  990.  *
  991.  * Side effects:
  992.  *    When the procedure returns, the X window associated with
  993.  *    tkwin is guaranteed to exist.  This may require the
  994.  *    window's ancestors to be created also.
  995.  *
  996.  *--------------------------------------------------------------
  997.  */
  998.  
  999. void
  1000. Tk_MakeWindowExist(tkwin)
  1001.     Tk_Window tkwin;        /* Token for window. */
  1002. {
  1003.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1004.     Window parent;
  1005.  
  1006.     if (winPtr->window != None) {
  1007.     return;
  1008.     }
  1009.  
  1010.     if (winPtr->flags & TK_TOP_LEVEL) {
  1011.     parent = XRootWindow(winPtr->display, winPtr->screenNum);
  1012.     } else {
  1013.     if (winPtr->parentPtr->window == None) {
  1014.         Tk_MakeWindowExist((Tk_Window) winPtr->parentPtr);
  1015.     }
  1016.     parent = winPtr->parentPtr->window;
  1017.     }
  1018.     winPtr->window = XCreateWindow(winPtr->display, parent,
  1019.         winPtr->changes.x, winPtr->changes.y,
  1020.         winPtr->changes.width, winPtr->changes.height,
  1021.         winPtr->changes.border_width, CopyFromParent,
  1022.         InputOutput, CopyFromParent, winPtr->dirtyAtts,
  1023.         &winPtr->atts);
  1024.     XSaveContext(winPtr->display, winPtr->window, tkWindowContext,
  1025.         (caddr_t) winPtr);
  1026.     winPtr->dirtyAtts = 0;
  1027.     winPtr->dirtyChanges &= ~(CWX|CWY|CWWidth|CWHeight|CWBorderWidth);
  1028.     if (winPtr->dirtyChanges != 0) {
  1029.     XConfigureWindow(winPtr->display, winPtr->window,
  1030.         winPtr->dirtyChanges, &winPtr->changes);
  1031.     winPtr->dirtyChanges = 0;
  1032.     }
  1033.  
  1034.     /*
  1035.      * Issue a ConfigureNotify event if there were deferred configuration
  1036.      * changes.
  1037.      */
  1038.  
  1039.     if (winPtr->flags & TK_NEED_CONFIG_NOTIFY) {
  1040.     winPtr->flags &= ~TK_NEED_CONFIG_NOTIFY;
  1041.     DoConfigureNotify(winPtr);
  1042.     }
  1043. }
  1044.  
  1045. /*
  1046.  *--------------------------------------------------------------
  1047.  *
  1048.  * Tk_UnmapWindow, etc. --
  1049.  *
  1050.  *    There are several procedures under here, each of which
  1051.  *    mirrors an existing X procedure.  In addition to performing
  1052.  *    the functions of the corresponding procedure, each
  1053.  *    procedure also updates the local window structure and
  1054.  *    synthesizes an X event (if the window's structure is being
  1055.  *    managed internally).
  1056.  *
  1057.  * Results:
  1058.  *    See the manual entries.
  1059.  *
  1060.  * Side effects:
  1061.  *    See the manual entries.
  1062.  *
  1063.  *--------------------------------------------------------------
  1064.  */
  1065.  
  1066. void
  1067. Tk_UnmapWindow(tkwin)
  1068.     Tk_Window tkwin;        /* Token for window to unmap. */
  1069. {
  1070.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1071.  
  1072.     if (!(winPtr->flags & TK_MAPPED)) {
  1073.     return;
  1074.     }
  1075.     winPtr->flags &= ~TK_MAPPED;
  1076.     XUnmapWindow(winPtr->display, winPtr->window);
  1077.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  1078.     XEvent event;
  1079.  
  1080.     event.type = UnmapNotify;
  1081.     event.xunmap.serial = LastKnownRequestProcessed(winPtr->display);
  1082.     event.xunmap.send_event = False;
  1083.     event.xunmap.display = winPtr->display;
  1084.     event.xunmap.event = winPtr->window;
  1085.     event.xunmap.window = winPtr->window;
  1086.     event.xunmap.from_configure = False;
  1087.     Tk_HandleEvent(&event);
  1088.     }
  1089. }
  1090.  
  1091. void
  1092. Tk_ConfigureWindow(tkwin, valueMask, valuePtr)
  1093.     Tk_Window tkwin;        /* Window to re-configure. */
  1094.     unsigned int valueMask;    /* Mask indicating which parts of
  1095.                  * *valuePtr are to be used. */
  1096.     XWindowChanges *valuePtr;    /* New values. */
  1097. {
  1098.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1099.  
  1100.     if ((winPtr->window == None) || !(winPtr->flags & TK_TOP_LEVEL)) {
  1101.     if (valueMask & CWX) {
  1102.         winPtr->changes.x = valuePtr->x;
  1103.     }
  1104.     if (valueMask & CWY) {
  1105.         winPtr->changes.y = valuePtr->y;
  1106.     }
  1107.     if (valueMask & CWWidth) {
  1108.         winPtr->changes.width = valuePtr->width;
  1109.     }
  1110.     if (valueMask & CWHeight) {
  1111.         winPtr->changes.height = valuePtr->height;
  1112.     }
  1113.     if (valueMask & CWBorderWidth) {
  1114.         winPtr->changes.border_width = valuePtr->border_width;
  1115.     }
  1116.     if (valueMask & CWSibling) {
  1117.         winPtr->changes.sibling = valuePtr->sibling;
  1118.     }
  1119.     if (valueMask & CWStackMode) {
  1120.         winPtr->changes.stack_mode = valuePtr->stack_mode;
  1121.     }
  1122.     }
  1123.  
  1124.     if (winPtr->window != None) {
  1125.     XConfigureWindow(winPtr->display, winPtr->window,
  1126.         valueMask, valuePtr);
  1127.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  1128.         DoConfigureNotify(winPtr);
  1129.     }
  1130.     } else {
  1131.     winPtr->dirtyChanges |= valueMask;
  1132.     winPtr->flags |= TK_NEED_CONFIG_NOTIFY;
  1133.     }
  1134. }
  1135.  
  1136. void
  1137. Tk_MoveWindow(tkwin, x, y)
  1138.     Tk_Window tkwin;        /* Window to move. */
  1139.     int x, y;            /* New location for window (within
  1140.                  * parent). */
  1141. {
  1142.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1143.  
  1144.     if (winPtr->window != None) {
  1145.     XMoveWindow(winPtr->display, winPtr->window, x, y);
  1146.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  1147.         winPtr->changes.x = x;
  1148.         winPtr->changes.y = y;
  1149.         DoConfigureNotify(winPtr);
  1150.     }
  1151.     } else {
  1152.     winPtr->changes.x = x;
  1153.     winPtr->changes.y = y;
  1154.     winPtr->dirtyChanges |= CWX|CWY;
  1155.     winPtr->flags |= TK_NEED_CONFIG_NOTIFY;
  1156.     }
  1157. }
  1158.  
  1159. void
  1160. Tk_ResizeWindow(tkwin, width, height)
  1161.     Tk_Window tkwin;        /* Window to resize. */
  1162.     unsigned int width, height;    /* New dimensions for window. */
  1163. {
  1164.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1165.  
  1166.     if (winPtr->window != None) {
  1167.     XResizeWindow(winPtr->display, winPtr->window, width, height);
  1168.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  1169.         winPtr->changes.width = width;
  1170.         winPtr->changes.height = height;
  1171.         DoConfigureNotify(winPtr);
  1172.     }
  1173.     } else {
  1174.     winPtr->changes.width = width;
  1175.     winPtr->changes.height = height;
  1176.     winPtr->dirtyChanges |= CWWidth|CWHeight;
  1177.     winPtr->flags |= TK_NEED_CONFIG_NOTIFY;
  1178.     }
  1179. }
  1180.  
  1181. void
  1182. Tk_MoveResizeWindow(tkwin, x, y, width, height)
  1183.     Tk_Window tkwin;        /* Window to move and resize. */
  1184.     int x, y;            /* New location for window (within
  1185.                  * parent). */
  1186.     unsigned int width, height;    /* New dimensions for window. */
  1187. {
  1188.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1189.  
  1190.     if (winPtr->window != None) {
  1191.     XMoveResizeWindow(winPtr->display, winPtr->window,
  1192.         x, y, width, height);
  1193.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  1194.         winPtr->changes.x = x;
  1195.         winPtr->changes.y = y;
  1196.         winPtr->changes.width = width;
  1197.         winPtr->changes.height = height;
  1198.         DoConfigureNotify(winPtr);
  1199.     }
  1200.     } else {
  1201.     winPtr->changes.x = x;
  1202.     winPtr->changes.y = y;
  1203.     winPtr->changes.width = width;
  1204.     winPtr->changes.height = height;
  1205.     winPtr->dirtyChanges |= CWX|CWY|CWWidth|CWHeight;
  1206.     winPtr->flags |= TK_NEED_CONFIG_NOTIFY;
  1207.     }
  1208. }
  1209.  
  1210. void
  1211. Tk_SetWindowBorderWidth(tkwin, width)
  1212.     Tk_Window tkwin;        /* Window to modify. */
  1213.     int width;            /* New border width for window. */
  1214. {
  1215.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1216.  
  1217.     winPtr->changes.border_width = width;
  1218.     if (winPtr->window != None) {
  1219.     XSetWindowBorderWidth(winPtr->display, winPtr->window, width);
  1220.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  1221.         DoConfigureNotify(winPtr);
  1222.     }
  1223.     } else {
  1224.     winPtr->dirtyChanges |= CWBorderWidth;
  1225.     winPtr->flags |= TK_NEED_CONFIG_NOTIFY;
  1226.     }
  1227. }
  1228.  
  1229. void
  1230. Tk_ChangeWindowAttributes(tkwin, valueMask, attsPtr)
  1231.     Tk_Window tkwin;        /* Window to manipulate. */
  1232.     unsigned long valueMask;    /* OR'ed combination of bits,
  1233.                  * indicating which fields of
  1234.                  * *attsPtr are to be used. */
  1235.     register XSetWindowAttributes *attsPtr;
  1236.                 /* New values for some attributes. */
  1237. {
  1238.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1239.  
  1240.     if (valueMask & CWBackPixmap) {
  1241.     winPtr->atts.background_pixmap = attsPtr->background_pixmap;
  1242.     }
  1243.     if (valueMask & CWBackPixel) {
  1244.     winPtr->atts.background_pixel = attsPtr->background_pixel;
  1245.     }
  1246.     if (valueMask & CWBorderPixmap) {
  1247.     winPtr->atts.border_pixmap = attsPtr->border_pixmap;
  1248.     }
  1249.     if (valueMask & CWBorderPixel) {
  1250.     winPtr->atts.border_pixel = attsPtr->border_pixel;
  1251.     }
  1252.     if (valueMask & CWBitGravity) {
  1253.     winPtr->atts.bit_gravity = attsPtr->bit_gravity;
  1254.     }
  1255.     if (valueMask & CWWinGravity) {
  1256.     winPtr->atts.win_gravity = attsPtr->win_gravity;
  1257.     }
  1258.     if (valueMask & CWBackingStore) {
  1259.     winPtr->atts.backing_store = attsPtr->backing_store;
  1260.     }
  1261.     if (valueMask & CWBackingPlanes) {
  1262.     winPtr->atts.backing_planes = attsPtr->backing_planes;
  1263.     }
  1264.     if (valueMask & CWBackingPixel) {
  1265.     winPtr->atts.backing_pixel = attsPtr->backing_pixel;
  1266.     }
  1267.     if (valueMask & CWOverrideRedirect) {
  1268.     winPtr->atts.override_redirect = attsPtr->override_redirect;
  1269.     }
  1270.     if (valueMask & CWSaveUnder) {
  1271.     winPtr->atts.save_under = attsPtr->save_under;
  1272.     }
  1273.     if (valueMask & CWEventMask) {
  1274.     winPtr->atts.event_mask = attsPtr->event_mask;
  1275.     }
  1276.     if (valueMask & CWDontPropagate) {
  1277.     winPtr->atts.do_not_propagate_mask
  1278.         = attsPtr->do_not_propagate_mask;
  1279.     }
  1280.     if (valueMask & CWColormap) {
  1281.     winPtr->atts.colormap = attsPtr->colormap;
  1282.     }
  1283.     if (valueMask & CWCursor) {
  1284.     winPtr->atts.cursor = attsPtr->cursor;
  1285.     }
  1286.  
  1287.     if (winPtr->window != None) {
  1288.     XChangeWindowAttributes(winPtr->display, winPtr->window,
  1289.         valueMask, attsPtr);
  1290.     } else {
  1291.     winPtr->dirtyAtts |= valueMask;
  1292.     }
  1293. }
  1294.  
  1295. void
  1296. Tk_SetWindowBackground(tkwin, pixel)
  1297.     Tk_Window tkwin;        /* Window to manipulate. */
  1298.     unsigned long pixel;    /* Pixel value to use for
  1299.                  * window's background. */
  1300. {
  1301.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1302.  
  1303.     winPtr->atts.background_pixel = pixel;
  1304.  
  1305.     if (winPtr->window != None) {
  1306.     XSetWindowBackground(winPtr->display, winPtr->window, pixel);
  1307.     } else {
  1308.     winPtr->dirtyAtts = (winPtr->dirtyAtts & ~CWBackPixmap)
  1309.         | CWBackPixel;
  1310.     }
  1311. }
  1312.  
  1313. void
  1314. Tk_SetWindowBackgroundPixmap(tkwin, pixmap)
  1315.     Tk_Window tkwin;        /* Window to manipulate. */
  1316.     Pixmap pixmap;        /* Pixmap to use for window's
  1317.                  * background. */
  1318. {
  1319.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1320.  
  1321.     winPtr->atts.background_pixmap = pixmap;
  1322.  
  1323.     if (winPtr->window != None) {
  1324.     XSetWindowBackgroundPixmap(winPtr->display,
  1325.         winPtr->window, pixmap);
  1326.     } else {
  1327.     winPtr->dirtyAtts = (winPtr->dirtyAtts & ~CWBackPixel)
  1328.         | CWBackPixmap;
  1329.     }
  1330. }
  1331.  
  1332. void
  1333. Tk_SetWindowBorder(tkwin, pixel)
  1334.     Tk_Window tkwin;        /* Window to manipulate. */
  1335.     unsigned long pixel;    /* Pixel value to use for
  1336.                  * window's border. */
  1337. {
  1338.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1339.  
  1340.     winPtr->atts.border_pixel = pixel;
  1341.  
  1342.     if (winPtr->window != None) {
  1343.     XSetWindowBorder(winPtr->display, winPtr->window, pixel);
  1344.     } else {
  1345.     winPtr->dirtyAtts = (winPtr->dirtyAtts & ~CWBorderPixmap)
  1346.         | CWBorderPixel;
  1347.     }
  1348. }
  1349.  
  1350. void
  1351. Tk_SetWindowBorderPixmap(tkwin, pixmap)
  1352.     Tk_Window tkwin;        /* Window to manipulate. */
  1353.     Pixmap pixmap;        /* Pixmap to use for window's
  1354.                  * border. */
  1355. {
  1356.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1357.  
  1358.     winPtr->atts.border_pixmap = pixmap;
  1359.  
  1360.     if (winPtr->window != None) {
  1361.     XSetWindowBorderPixmap(winPtr->display,
  1362.         winPtr->window, pixmap);
  1363.     } else {
  1364.     winPtr->dirtyAtts = (winPtr->dirtyAtts & ~CWBorderPixel)
  1365.         | CWBorderPixmap;
  1366.     }
  1367. }
  1368.  
  1369. void
  1370. Tk_DefineCursor(tkwin, cursor)
  1371.     Tk_Window tkwin;        /* Window to manipulate. */
  1372.     Cursor cursor;        /* Cursor to use for window (may be None). */
  1373. {
  1374.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1375.  
  1376.     winPtr->atts.cursor = cursor;
  1377.  
  1378.     if (winPtr->window != None) {
  1379.     XDefineCursor(winPtr->display, winPtr->window, cursor);
  1380.     } else {
  1381.     winPtr->dirtyAtts = winPtr->dirtyAtts | CWCursor;
  1382.     }
  1383. }
  1384.  
  1385. void
  1386. Tk_UndefineCursor(tkwin)
  1387.     Tk_Window tkwin;        /* Window to manipulate. */
  1388. {
  1389.     Tk_DefineCursor(tkwin, None);
  1390. }
  1391.  
  1392. /*
  1393.  *----------------------------------------------------------------------
  1394.  *
  1395.  * DoConfigureNotify --
  1396.  *
  1397.  *    Generate a ConfigureNotify event describing the current
  1398.  *    configuration of a window.
  1399.  *
  1400.  * Results:
  1401.  *    None.
  1402.  *
  1403.  * Side effects:
  1404.  *    An event is generated and processed by Tk_HandleEvent.
  1405.  *
  1406.  *----------------------------------------------------------------------
  1407.  */
  1408.  
  1409. static void
  1410. DoConfigureNotify(winPtr)
  1411.     register TkWindow *winPtr;        /* Window whose configuration
  1412.                      * was just changed. */
  1413. {
  1414.     XEvent event;
  1415.  
  1416.     event.type = ConfigureNotify;
  1417.     event.xconfigure.serial = LastKnownRequestProcessed(winPtr->display);
  1418.     event.xconfigure.send_event = False;
  1419.     event.xconfigure.display = winPtr->display;
  1420.     event.xconfigure.event = winPtr->window;
  1421.     event.xconfigure.window = winPtr->window;
  1422.     event.xconfigure.x = winPtr->changes.x;
  1423.     event.xconfigure.y = winPtr->changes.y;
  1424.     event.xconfigure.width = winPtr->changes.width;
  1425.     event.xconfigure.height = winPtr->changes.height;
  1426.     event.xconfigure.border_width = winPtr->changes.border_width;
  1427.     if (winPtr->changes.stack_mode == Above) {
  1428.     event.xconfigure.above = winPtr->changes.sibling;
  1429.     } else {
  1430.     event.xconfigure.above = None;
  1431.     }
  1432.     event.xconfigure.override_redirect = winPtr->atts.override_redirect;
  1433.     Tk_HandleEvent(&event);
  1434. }
  1435.  
  1436. /*
  1437.  *----------------------------------------------------------------------
  1438.  *
  1439.  * Tk_SetClass --
  1440.  *
  1441.  *    This procedure is used to give a window a class.
  1442.  *
  1443.  * Results:
  1444.  *    None.
  1445.  *
  1446.  * Side effects:
  1447.  *    A new class is stored for tkwin, replacing any existing
  1448.  *    class for it.
  1449.  *
  1450.  *----------------------------------------------------------------------
  1451.  */
  1452.  
  1453. void
  1454. Tk_SetClass(tkwin, className)
  1455.     Tk_Window tkwin;        /* Token for window to assign class. */
  1456.     char *className;        /* New class for tkwin. */
  1457. {
  1458.     register TkWindow *winPtr = (TkWindow *) tkwin;
  1459.  
  1460.     winPtr->classUid = Tk_GetUid(className);
  1461.     if (winPtr->flags & TK_TOP_LEVEL) {
  1462.     TkWmSetClass(winPtr);
  1463.     }
  1464. }
  1465.  
  1466. /*
  1467.  *----------------------------------------------------------------------
  1468.  *
  1469.  * Tk_NameToWindow --
  1470.  *
  1471.  *    Given a string name for a window, this procedure
  1472.  *    returns the token for the window, if there exists a
  1473.  *    window corresponding to the given name.
  1474.  *
  1475.  * Results:
  1476.  *    The return result is either a token for the window corresponding
  1477.  *    to "name", or else NULL to indicate that there is no such
  1478.  *    window.  In this case, an error message is left in interp->result.
  1479.  *
  1480.  * Side effects:
  1481.  *    None.
  1482.  *
  1483.  *----------------------------------------------------------------------
  1484.  */
  1485.  
  1486. Tk_Window
  1487. Tk_NameToWindow(interp, pathName, tkwin)
  1488.     Tcl_Interp *interp;        /* Where to report errors. */
  1489.     char *pathName;        /* Path name of window. */
  1490.     Tk_Window tkwin;        /* Token for window:  name is assumed to
  1491.                  * belong to the same main window as tkwin. */
  1492. {
  1493.     Tcl_HashEntry *hPtr;
  1494.  
  1495.     hPtr = Tcl_FindHashEntry(&((TkWindow *) tkwin)->mainPtr->nameTable,
  1496.         pathName);
  1497.     if (hPtr == NULL) {
  1498.     Tcl_AppendResult(interp, "bad window path name \"",
  1499.         pathName, "\"", (char *) NULL);
  1500.     return NULL;
  1501.     }
  1502.     return (Tk_Window) Tcl_GetHashValue(hPtr);
  1503. }
  1504.  
  1505. /*
  1506.  *----------------------------------------------------------------------
  1507.  *
  1508.  * Tk_DisplayName --
  1509.  *
  1510.  *    Return the textual name of a window's display.
  1511.  *
  1512.  * Results:
  1513.  *    The return value is the string name of the display associated
  1514.  *    with tkwin.
  1515.  *
  1516.  * Side effects:
  1517.  *    None.
  1518.  *
  1519.  *----------------------------------------------------------------------
  1520.  */
  1521.  
  1522. char *
  1523. Tk_DisplayName(tkwin)
  1524.     Tk_Window tkwin;        /* Window whose display name is desired. */
  1525. {
  1526.     return ((TkWindow *) tkwin)->dispPtr->name;
  1527. }
  1528.